package com.netty.test.edge;

import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;

import com.hashimoto.core.handler.business.EdgeHandler;
import com.hashimoto.core.handler.decodec.CodecAdapter;
import com.hashimoto.core.message.EdgeInitiativePushSignal;
import com.hashimoto.core.remote.client.ClientConfig;
import com.hashimoto.core.remote.client.ClientType;
import com.hashimoto.core.remote.client.edge.EdgeCallback;
import com.hashimoto.core.remote.client.edge.EdgeClient;
import com.hashimoto.core.remote.client.edge.EdgeProcessHandler;
import com.hashimoto.core.remote.client.edge.NettyEdgeProcessHandler;
import com.hashimoto.core.util.GsonUtil;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultThreadFactory;

public class EdgeNettyClient extends EdgeClient {

	private static final NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(2,
			new DefaultThreadFactory("NettyClientWorker", true));

	private Bootstrap bootstrap;

	private volatile Channel channel; // volatile, please copy reference to use

	private ClientConfig config;

	private EdgeProcessHandler hander;

	private EdgeCallback callBack;

	private enum State {

	}

	@Override
	public void clientConfig(ClientConfig config) {
		this.config = config;
	}

	@Override
	public SocketAddress remoteAddress() {
		return null;
	}

	@Override
	public void excepton(Throwable t) {

	}

	@SuppressWarnings("rawtypes")
	@Override
	public void start() {
		hander = new NettyEdgeProcessHandler();
		hander.edgeCallback(callBack);
		hander.setConfig(config);
		bootstrap = new Bootstrap();
		bootstrap.group(nioEventLoopGroup).option(ChannelOption.SO_KEEPALIVE, true)
				.option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
				.channel(NioSocketChannel.class);

		if (this.config.getConnectTimeout() < 3000) {
			bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000);
		} else {
			bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.config.getConnectTimeout());
		}

		bootstrap.handler(new ChannelInitializer() {

			@Override
			protected void initChannel(Channel ch) throws Exception {
				CodecAdapter adapter = new CodecAdapter();
				ch.pipeline()// .addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
						.addLast("ping", new IdleStateHandler(0, 0, 19, TimeUnit.SECONDS))
						.addLast("decoder", adapter.getDecode()).addLast("encoder", adapter.getEncode())
						.addLast("handler", new EdgeHandler(hander));
			}
		});

		bootstrap.remoteAddress(this.config.getRemoteHost(), this.config.getRemotePort());
		ChannelFuture future = bootstrap.connect();
		boolean ret = future.awaitUninterruptibly(this.config.getConnectTimeout(), TimeUnit.MILLISECONDS);
		if (ret && future.isSuccess()) {
			this.channel = future.channel();
		} else {

		}
	}

	@Override
	public void stop() {

	}

	@Override
	public boolean isActive() {
		return this.channel != null ? this.channel.isActive() : false;
	}

	@Override
	public SocketAddress localAddress() {

		return this.isActive() ? channel.localAddress() : null;
	}

	@Override
	public void setReceivedCallback(EdgeCallback callback) {
		this.callBack = callback;
	}

	public static void main(String[] args) {
		EdgeNettyClient client = new EdgeNettyClient();
		ClientConfig config = new ClientConfig();
		config.setClientId(124563);
		config.setConnectTimeout(300000);
		config.setPassword("123446");
		config.setUserType(ClientType.EDGE);
		config.setUsrname("12312");
		config.setRemoteHost("127.0.0.1");
		config.setRemotePort(9999);
		client.clientConfig(config);

//		client.setReceivedCallback(new EdgeCallback() {
//
//			@Override
//			public void onMessage(String interfaceName, long msgId, int callId, byte[] data) {
//				System.out.println(new String(data));
//				System.out.println("-----------------------------------");
//				client.send(interfaceName, msgId, 200, callId, data);
//
//			}
//
//			@Override
//			public void flushRegistry(byte[] data) {
//
//			}
//		});

		try {
			client.start();
			for (int i = 0; i < 10; i++) {
				client.report(10000, String.valueOf(i));

			}

			Thread.sleep(100000000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	@Override
	public void report(int eventKey, Object data) {
		EdgeInitiativePushSignal signal = new EdgeInitiativePushSignal();
		signal.setParkId(this.config.getClientId());
		signal.setEventKey(eventKey);
		signal.setMsgId(System.currentTimeMillis());
		signal.setData(data != null ? GsonUtil.toJson(data).getBytes() : new byte[0]);
		ChannelFuture future = channel.writeAndFlush(signal);
		future.addListener(mFuture -> {

		});
	}

	@Override
	public void send(String interfaceName, Long msgId, int code, int objectivesId, Object data) {

	}

	@Override
	public void registry(Object data) {
		// TODO Auto-generated method stub
		
	}

}
